import EventEmitter from "events";
import type TypedEmitter from "typed-emitter";
import ArRTC from "ar-rtc-sdk";
import type {
  ConfigParameters,
  ConnectionDisconnectedReason,
  ConnectionState,
  IArRTCClient,
  IArRTCRemoteUser,
  SDK_MODE,
  ICameraVideoTrack,
  IMicrophoneAudioTrack,
  ILocalTrack,
  ClientRole,
  VideoEncoderConfigurationPreset,
  VideoPlayerConfig,
  ILocalVideoTrack,
  ILocalAudioTrack,
  ScreenEncoderConfigurationPreset,
  RemoteStreamType,
} from "ar-rtc-sdk";
import { RTCPublishState, RTCServiceEvents } from "./liveType";

export class RTCService extends (EventEmitter as unknown as new () => TypedEmitter<RTCServiceEvents>) {
  /**
   * RTC 模式
   *
   * @private
   * @type {SDK_MODE}
   */
  private _rtcMode: SDK_MODE = "rtc";

  /**
   * RTC 客户端
   *
   * @private
   * @type {(IArRTCClient | null)}
   */
  private _rtcClient: IArRTCClient | null = null;

  /**
   * 是否开启双流
   *
   * @private
   * @type {boolean}
   */
  private _enableDualStream: boolean = false;

  /**
   * RTC 私有化配置
   *
   * @private
   * @type {ConfigParameters}
   */
  private _rtcConfig: ConfigParameters = {};

  // -----------    Media Device start    ----------
  private _cameraList: MediaDeviceInfo[] = [];
  private _microphoneList: MediaDeviceInfo[] = [];
  private _speakerList: MediaDeviceInfo[] = [];

  private _currentCameraId: string = "";
  private _currentMicrophoneId: string = "";
  private _currentSpeakerId: string = "";
  // -----------    Media Device stop    ----------

  // 本地轨道
  private _localVideoTrack: ICameraVideoTrack | null = null;
  private _localAudioTrack: IMicrophoneAudioTrack | null = null;
  private _localVideoProfile: VideoEncoderConfigurationPreset = "360p"; // 360p 480p_1 720p 1080p
  private _localVideoPlayerConfig: VideoPlayerConfig = {
    fit: "contain",
  };
  // 发布状态
  private _publishedVideoState: RTCPublishState = RTCPublishState.IDLE;
  private _publishedAudioState: RTCPublishState = RTCPublishState.IDLE;

  // 用户 ID 对应的用户信息
  private _remoteUsers: Map<string, IArRTCRemoteUser> = new Map();

  /**
   * 是否已经登录 RTC
   *
   * @private
   * @type {boolean}
   */
  private _isLogin: boolean = false;

  constructor() {
    super();
    this._onConnectionStateChange = this._onConnectionStateChange.bind(this);
    this._onUserJoin = this._onUserJoin.bind(this);
    this._onUserLeft = this._onUserLeft.bind(this);
    this._onUserPublished = this._onUserPublished.bind(this);
    this._onUserUnpublished = this._onUserUnpublished.bind(this);

    this._onTokenWillExpired = this._onTokenWillExpired.bind(this);
    this._onTokenDidExpired = this._onTokenDidExpired.bind(this);
  }

  get hasVideoTrack() {
    return !!this._localVideoTrack;
  }

  get hasAudioTrack() {
    return !!this._localAudioTrack;
  }

  get currentMicrophone() {
    return this._currentMicrophoneId;
  }

  get currentCamera() {
    return this._currentCameraId;
  }

  get currentSpeaker() {
    return this._currentSpeakerId;
  }

  setParameters(options: ConfigParameters) {
    this._rtcConfig = options;
    this._rtcClient?.setParameters(options);
  }

  /**
   * 设置是否开启双流
   *
   * @param {boolean} enable
   */
  setDualStreamEnable(enable: boolean) {
    this._enableDualStream = enable;

    if (this._enableDualStream) {
      this._rtcClient?.enableDualStream();
    } else {
      this._rtcClient?.disableDualStream();
    }
  }
  /**
   * token 更新
   */
  updataToken(token: string) {
    if (this._rtcClient) {
      this._rtcClient.renewToken(token);
    }
  }
  async joinChannel(
    appid: string,
    channel: string,
    token: string | null,
    uid?: string | null | undefined,
    role?: ClientRole
  ) {
    if (!this._isLogin) {
      this._rtcClient = ArRTC.createClient({
        codec: "h264",
        mode: this._rtcMode,
      });
      // 直播模式下设置用户角色
      if (this._rtcMode === "live") {
        this._rtcClient.setClientRole(role || "audience");
      }
      // 开启双流
      //   this.setDualStreamEnable(true);
      // 开启语音检测
      //   this._rtcClient.enableAudioVolumeIndicator();
      this._rtcClient?.setParameters({
        ...this._rtcConfig,
        AudioVolumeInterval: 300,
      });
      this._bindRTCEvents();
      await this._rtcClient?.join(appid, channel, token, uid);
      this._isLogin = true;
      // 自动发布
      if (this._rtcMode === "live") {
        role === "host" && (await this._publishLocalTracks());
      } else {
        await this._publishLocalTracks();
      }
    }
  }

  leaveChannel() {
    // 释放麦克风与摄像头
    this.stopCameraPreview();
    this.stopMicrophone();
    if (this._isLogin) {
      this._unbindRTCEvents();
      this._rtcClient?.leave();
      this._rtcClient = null;
      this._resetFlag();
    }
  }

  /**
   * 批量设置订阅用户的大小流
   *
   * @param {string[]} userIds
   * @param {RemoteStreamType} streamType
   */
  setUserVideoStreamType(userIds: string[], streamType: RemoteStreamType) {
    userIds.forEach((userId) => {
      console.log(">>> setUserVideoStreamType", userId, streamType);
      this._rtcClient?.setRemoteVideoStreamType(userId, streamType);
    });
  }

  private _resetFlag() {
    this._rtcConfig = {};
    this._publishedVideoState = RTCPublishState.IDLE;
    this._publishedAudioState = RTCPublishState.IDLE;
    this._remoteUsers.clear();
    this._isLogin = false;
    this._cameraList = [];
    this._microphoneList = [];
    this._speakerList = [];
    this._currentCameraId = "";
    this._currentMicrophoneId = "";
    this._currentSpeakerId = "";
    this._localVideoTrack = null;
    this._localAudioTrack = null;
    this._localVideoProfile = "1080p";
    this._localVideoPlayerConfig = {};
    this._enableDualStream = false;
  }

  /**
   * /////////////////////////////////////////////////////////////////////////////////
   * //
   * //                                   设备相关
   * //
   * /////////////////////////////////////////////////////////////////////////////////
   */

  /**
   * 获取媒体输入的设备列表
   *
   * @returns {*}
   */
  async getMediaDeviceList() {
    // 获取媒体输入设备
    const mediaDevices = await ArRTC.getDevices();
    const cameraList: MediaDeviceInfo[] = [];
    const microphoneList: MediaDeviceInfo[] = [];
    const speakerList: MediaDeviceInfo[] = [];
    mediaDevices.forEach((deviceInfo) => {
      if (deviceInfo.kind === "audioinput") {
        microphoneList.push(deviceInfo);
      } else if (deviceInfo.kind === "videoinput") {
        cameraList.push(deviceInfo);
      } else if (deviceInfo.kind === "audiooutput") {
        speakerList.push(deviceInfo);
      }
    });
    // 设置默认设备
    if (cameraList.length > 0) {
      const cameraInfo = cameraList[0];
      if (cameraInfo && cameraInfo.deviceId) {
        this.setCurrentCameraId(cameraInfo.deviceId);
      }
    }
    if (microphoneList.length > 0) {
      const micInfo = microphoneList[0];
      if (micInfo && micInfo.deviceId) {
        this.setCurrentMicrophoneId(micInfo.deviceId);
      }
    }
    if (speakerList.length > 0) {
      const speakerInfo = speakerList[0];
      if (speakerInfo && speakerInfo.deviceId) {
        this.setCurrentSpeakerId(speakerInfo.deviceId);
      }
    }
    this._cameraList = cameraList;
    this._microphoneList = microphoneList;
    this._speakerList = speakerList;

    return {
      cameraList,
      microphoneList,
      speakerList,
    };
  }

  /**
   * 获取摄像头
   *
   * @returns {*}
   */
  async getCameraList() {
    // 获取媒体输入设备
    const cameraList = await ArRTC.getCameras();

    // 设置默认设备
    if (cameraList.length > 0) {
      const cameraInfo = cameraList[0];
      if (cameraInfo && cameraInfo.deviceId) {
        this.setCurrentCameraId(cameraInfo.deviceId);
      }
    }
    this._cameraList = cameraList;

    return cameraList;
  }

  /**
   * 获取麦克风
   *
   * @returns {*}
   */
  async getMicrophoneList() {
    // 获取媒体输入设备
    const microphoneList = await ArRTC.getMicrophones();

    // 设置默认设备
    if (microphoneList.length > 0) {
      const micInfo = microphoneList[0];
      if (micInfo && micInfo.deviceId) {
        this.setCurrentMicrophoneId(micInfo.deviceId);
      }
    }
    this._microphoneList = microphoneList;

    return microphoneList;
  }

  /**
   * 获取扬声器
   *
   * @returns {*}
   */
  async getSpeakerList() {
    // 获取媒体输入设备
    const speakerList = await ArRTC.getPlaybackDevices();

    // 设置默认设备
    if (speakerList.length > 0) {
      const speakerInfo = speakerList[0];
      if (speakerInfo && speakerInfo.deviceId) {
        this.setCurrentSpeakerId(speakerInfo.deviceId);
      }
    }
    this._speakerList = speakerList;

    return speakerList;
  }

  /**
   * 设置摄像头 ID
   *
   * @param {string} deviceId
   */
  setCurrentCameraId(deviceId: string) {
    this._currentCameraId = deviceId;
    if (this.hasVideoTrack) {
      this._localVideoTrack!.setDevice(deviceId);
    }
  }

  /**
   * 设置麦克风 ID
   *
   * @param {string} deviceId
   */
  setCurrentMicrophoneId(deviceId: string) {
    this._currentMicrophoneId = deviceId;
    if (this.hasAudioTrack) {
      this._localAudioTrack!.setDevice(deviceId);
    }
  }

  /**
   * 设置扬声器 ID
   *
   * @param {string} deviceId
   */
  setCurrentSpeakerId(deviceId: string) {
    this._currentSpeakerId = deviceId;
  }

  /**
   * 设置视频分辨率
   *
   * @param {VideoEncoderConfigurationPreset} videoProfile
   */
  async setLocalVideoProfile(videoProfile: VideoEncoderConfigurationPreset) {
    // VideoEncoderConfiguration
    this._localVideoProfile = videoProfile || "480p_1";
    if (this.hasVideoTrack) {
      this._localVideoTrack!.setEncoderConfiguration(this._localVideoProfile);
    }
  }

  // beta
  async startMediaAndPublish(element: string | HTMLElement) {
    await this._startMedia();
    this._startLocalPreview(element);
    // 如果还有没有发布的轨道，将其发布
    this._publishLocalTracks();
  }

  /**
   * 打开本地摄像头
   *
   * @param {(string | HTMLElement)} element
   */
  async startCameraPreview(element: string | HTMLElement) {
    if (!this.hasVideoTrack) {
      await this._startLocalVideo();
    }
    this._startLocalPreview(element);
    // 如果还有没有发布的轨道，将其发布
    this._publishLocalTracks();
  }

  /**
   *
   *
   */
  async stopCameraPreview() {
    if (this.hasVideoTrack) {
      this._stopLocalPreview();
    }
  }

  async startMicrophone() {
    await this._startLocalAudio();
    // 如果还有没有发布的轨道，将其发布
    this._publishLocalTracks();
  }

  stopMicrophone() {
    if (this.hasAudioTrack) {
      this._stopLocalAudio();
    }
  }

  getLocalAudioVolumeLevel() {
    return this._localAudioTrack ? this._localAudioTrack.getVolumeLevel() : 0;
  }

  async muteLocalCamera(mute: boolean) {
    // 打开摄像头并且没有轨道时
    if (!mute && !this.hasVideoTrack) {
      await this._startLocalVideo();
      this._publishLocalTracks();
    } else {
      this._muteLocalVideo(mute);
    }
  }

  async muteLocalMicrophone(mute: boolean) {
    // 打开摄像头并且没有轨道时
    if (!mute && !this.hasAudioTrack) {
      await this._startLocalAudio();
      this._publishLocalTracks();
    } else {
      this._muteLocalAudio(mute);
    }
  }

  /**
   * 开始预览本地摄像头
   *
   * @param {(string | HTMLElement)} element
   * @param {VideoPlayerConfig} [config]
   */
  async startRemotePreview(
    userId: string,
    element: string | HTMLElement,
    config?: VideoPlayerConfig
  ) {
    const remoteUserTrack = this._remoteUsers.get(userId);
    console.log(`是否找到用户 ${userId} 的视频轨道 ${!!remoteUserTrack}`);
    if (remoteUserTrack) {
      console.log("videoTrack ", remoteUserTrack.videoTrack);
      remoteUserTrack.videoTrack?.play(element, config);
    }
  }
  destroy() {
    this.leaveChannel();
  }

  // beta
  private async _startMedia() {
    const [audioTrack, videoTrack] =
      await ArRTC.createMicrophoneAndCameraTracks(
        {},
        {
          cameraId: this._currentCameraId ?? "",
          encoderConfig: this._localVideoProfile,
        }
      );
    if (!this._localVideoTrack) {
      this._localVideoTrack = videoTrack;
    } else {
      videoTrack.close();
    }
    if (!this._localAudioTrack) {
      this._localAudioTrack = audioTrack;
    } else {
      audioTrack.close();
    }
  }

  /**
   * 打开本地摄像头
   *
   * @param {string} deviceId
   * @param {VideoEncoderConfigurationPreset} videoProfile
   */
  private async _startLocalVideo() {
    const videoTrack = await ArRTC.createCameraVideoTrack({
      cameraId: this._currentCameraId ?? "",
      encoderConfig: this._localVideoProfile,
    });
    if (!this._localVideoTrack) {
      this._localVideoTrack = videoTrack;
    } else {
      videoTrack.close();
    }
  }

  private async _startLocalAudio() {
    const audioTrack = await ArRTC.createMicrophoneAudioTrack({
      microphoneId: this._currentMicrophoneId ?? "",
    });
    if (!this._localAudioTrack) {
      this._localAudioTrack = audioTrack;
    } else {
      audioTrack.close();
    }
  }

  private _stopLocalAudio() {
    if (this.hasAudioTrack) {
      this._localAudioTrack!.close();
      this._localAudioTrack = null;
    }
  }

  /**
   * 开始预览本地摄像头
   *
   * @param {(string | HTMLElement)} element
   * @param {VideoPlayerConfig} [config]
   */
  private async _startLocalPreview(element: string | HTMLElement) {
    if (this.hasVideoTrack) {
      this._localVideoTrack!.play(element, this._localVideoPlayerConfig);
    }
  }

  /**
   * 结束预览本地摄像头
   */
  private async _stopLocalPreview() {
    this._localVideoTrack!.close();
    this._localVideoTrack = null;
  }

  /**
   * 禁用本地摄像头
   *
   * @param {boolean} mute
   */
  private _muteLocalVideo(mute: boolean) {
    if (this._localVideoTrack) {
      this._localVideoTrack.setMuted(mute);
    }
  }

  /**
   * 禁用本地麦克风
   *
   * @param {boolean} mute
   */
  private _muteLocalAudio(mute: boolean) {
    if (this._localAudioTrack) {
      this._localAudioTrack.setMuted(mute);
    }
  }

  private async _publishLocalTracks() {
    if (this._isLogin) {
      // 发布视频
      if (
        this._publishedVideoState === RTCPublishState.IDLE &&
        this._localVideoTrack
      ) {
        try {
          this._publishedVideoState = RTCPublishState.PUBLISHING;
          await this._publishTracks([this._localVideoTrack]);
          this._publishedVideoState = RTCPublishState.PUBLISHED;
        } catch (err) {
          this._publishedVideoState = RTCPublishState.IDLE;
          throw err;
        }
      }
      // 发布音频
      if (
        this._publishedAudioState === RTCPublishState.IDLE &&
        this._localAudioTrack
      ) {
        try {
          this._publishedAudioState = RTCPublishState.PUBLISHING;
          await this._publishTracks([this._localAudioTrack]);
          this._publishedAudioState = RTCPublishState.PUBLISHED;
        } catch (err) {
          this._publishedAudioState = RTCPublishState.IDLE;
          throw err;
        }
      }
    }
  }

  /**
   *
   *
   * @param {(Array<ICameraVideoTrack | IMicrophoneAudioTrack>)} tracks
   */
  private async _publishTracks(
    tracks: Array<ICameraVideoTrack | IMicrophoneAudioTrack>
  ) {
    if (this._isLogin) {
      await this._rtcClient?.publish(tracks);
    }
  }

  private _onConnectionStateChange(
    curState: ConnectionState,
    revState: ConnectionState,
    reason?: ConnectionDisconnectedReason
  ) {
    console.log(">>>RTC connectionStateChange<<<", curState, revState, reason);
    this.emit("CconnectionStateChange", curState, revState, reason);
  }

  private _onUserJoin(user: IArRTCRemoteUser) {
    if (!this._remoteUsers.get(user.uid)) {
      this._remoteUsers.set(user.uid, user);
    }
    this.emit("userJoin", user);
  }

  private _onUserLeft(user: IArRTCRemoteUser, reason: string) {
    if (this._remoteUsers.get(user.uid)) {
      this._remoteUsers.delete(user.uid);
    }
    this.emit("userLeft", user, reason);
  }

  private async _onUserPublished(
    user: IArRTCRemoteUser,
    mediaType: "audio" | "video"
  ) {
    console.log(`用户 ${user.uid} 发布了 ${mediaType} Track，开始订阅`);

    await this._rtcClient?.subscribe(user, mediaType);
    console.log(`订阅 ${user.uid} 的 ${mediaType} Track 成功`);
    if (mediaType === "audio") {
      user.audioTrack?.play();
    } else {
    }
    this.emit("userPublished", user, mediaType);
  }

  private _onUserUnpublished(
    user: IArRTCRemoteUser,
    mediaType: "audio" | "video"
  ) {
    this.emit("userUnpublished", user, mediaType);
  }
  private _onTokenWillExpired() {
    this.emit("RTCTokenWillExpired");
  }
  private _onTokenDidExpired() {
    this.emit("RTCTokenDidExpired");
  }
  private _bindRTCEvents() {
    this._rtcClient?.on(
      "connection-state-change",
      this._onConnectionStateChange
    );
    this._rtcClient?.on("user-joined", this._onUserJoin);
    this._rtcClient?.on("user-left", this._onUserLeft);
    this._rtcClient?.on("user-published", this._onUserPublished);
    this._rtcClient?.on("user-unpublished", this._onUserUnpublished);

    this._rtcClient?.on(
      "token-privilege-will-expire",
      this._onTokenWillExpired
    );
    this._rtcClient?.on("token-privilege-did-expire", this._onTokenDidExpired);
  }

  private _unbindRTCEvents() {
    this._rtcClient?.off(
      "connection-state-change",
      this._onConnectionStateChange
    );
    this._rtcClient?.off("user-joined", this._onUserJoin);
    this._rtcClient?.off("user-left", this._onUserLeft);
    this._rtcClient?.off("user-published", this._onUserPublished);
    this._rtcClient?.off("user-unpublished", this._onUserUnpublished);

    this._rtcClient?.on(
      "token-privilege-will-expire",
      this._onTokenWillExpired
    );
    this._rtcClient?.on("token-privilege-did-expire", this._onTokenDidExpired);
  }
}
